home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
usenet
/
sources
/
volume2
/
editors
/
stevie.3
< prev
next >
Wrap
Text File
|
1988-12-02
|
59KB
|
2,343 lines
Path: xanth!mcnc!gatech!bloom-beacon!mit-eddie!ll-xn!adelie!infinet!ulowell!page
From: page@swan.ulowell.edu (Bob Page)
Newsgroups: comp.sources.amiga
Subject: v02i083: stevie - vi editor clone, Part03/04
Message-ID: <10421@swan.ulowell.edu>
Date: 2 Dec 88 01:44:29 GMT
Organization: University of Lowell, Computer Science Dept.
Lines: 2332
Approved: page@swan.ulowell.edu
Submitted-by: grwalter@watcgl.waterloo.edu
Posting-number: Volume 2, Issue 83
Archive-name: editors/stevie.3
# This is a shell archive.
# Remove everything above and including the cut line.
# Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# screen.c
# search.c
# source.doc
# stevie.doc
# stevie.h
# term.h
# updateNextscreen.c
# updateRealscreen.c
# This archive created: Thu Dec 1 20:37:59 1988
cat << \SHAR_EOF > screen.c
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!watcgl!grwalter
*/
#include "stevie.h"
/*
* The following variable is set (in cursupdate) to the number of physical
* lines taken by the line the cursor is on. We use this to avoid extra calls
* to plines(). The optimized routines updateline() and redrawline()
* make sure that the size of the cursor line hasn't changed. If so, lines below
* the cursor will move up or down and we need to call the routines
* updateNextscreen() and updateRealscreen() to examine the entire screen.
*/
static int Cline_size; /* size (in rows) of the cursor line */
static int Cline_row; /* starting row of the cursor line */
/*
* updateline() - like updateNextscreen() but only for cursor line
*
* This determines whether or not we need to call updateNextscreen() to examine the
* entire screen for changes. This occurs if the size of the cursor line
* (in rows) hasn't changed.
*/
void
updateline()
{
int row, col;
register char *screenp;
LPTR memp;
register char *nextrow;
char extra[16];
int nextra = 0;
char c;
int n;
bool_t eof;
MustRedrawLine = TRUE;
#ifndef AMIGA
if (MustRedrawScreen) {
msg("STEVIE internal error: updateline called");
sleep(5);
}
#endif
screenp = Nextscreen + (Cline_row * Columns);
memp = *Curschar;
memp.index = 0;
eof = FALSE;
col = 0;
row = Cline_row;
while (!eof) {
/* Get the next character to put on the screen. */
/*
* The 'extra' array contains the extra stuff that is inserted to
* represent special characters (tabs, and other non-printable stuff.
* The order in the 'extra' array is reversed.
*/
if (nextra > 0)
c = extra[--nextra];
else {
c = gchar(&memp);
if (inc(&memp) == -1)
eof = TRUE;
/*
* when getting a character from the file, we may have to turn it
* into something else on the way to putting it into
* 'Nextscreen'.
*/
if (c == TAB && !P(P_LS)) {
strcpy(extra, " ");
/* tab amount depends on current column */
nextra = ((P(P_TS) - 1) - col % P(P_TS));
c = ' ';
} else if (c == NUL && P(P_LS)) {
extra[0] = NUL;
nextra = 1;
c = '$';
} else if (c != NUL && (n = chars[c].ch_size) > 1) {
char *p;
nextra = 0;
p = chars[c].ch_str;
/* copy 'ch-str'ing into 'extra' in reverse */
while (n > 1)
extra[nextra++] = p[--n];
c = p[0];
}
}
if (c == NUL) {
row++;
/* get pointer to start of next row */
nextrow = &Nextscreen[row * Columns];
/* blank out the rest of this row */
while (screenp != nextrow)
*screenp++ = ' ';
col = 0;
break;
}
if (col >= Columns) {
row++;
col = 0;
}
/* store the character in Nextscreen */
*screenp++ = c;
col++;
}
if ((row - Cline_row) == Cline_size)
updateNextscreen();
}
/*
* redrawline
*
* Like updateRealscreen() but only for the cursor line.
*/
void
redrawline()
{
register char *np = Nextscreen + (Cline_row * Columns);
register char *rp = Realscreen + (Cline_row * Columns);
register char *endline;
int row, col;
int gorow = -1, gocol = -1;
if (RedrawingDisabled)
return;
if (!MustRedrawLine && !MustRedrawScreen)
return;
if (MustRedrawScreen) {
msg("STEVIE internal error: redrawline called");
sleep(5);
}
endline = np + (Cline_size * Columns);
row = Cline_row;
col = 0;
outstr(T_CI); /* disable cursor */
for (; np < endline; np++, rp++) {
/* If desired screen (contents of Nextscreen) does not */
/* match what's really there, put it there. */
if (*np != *rp) {
/* if we are positioned at the right place, */
/* we don't have to use windgoto(). */
if (gocol != col || gorow != row) {
/*
* If we're just off by one, don't send an entire esc. seq.
* (this happens a lot!)
*/
if (gorow == row && gocol + 1 == col) {
outchar(*(np - 1));
gocol++;
} else
windgoto(gorow = row, gocol = col);
}
outchar(*rp = *np);
gocol++;
}
if (++col >= Columns) {
col = 0;
row++;
}
}
outstr(T_CV); /* enable cursor again */
MustRedrawScreen = FALSE;
}
void
screenclear()
{
char *rp, *np;
char *end;
outstr(T_ED); /* clear the display */
rp = Realscreen;
end = Realscreen + Rows * Columns;
np = Nextscreen;
/* blank out the stored screens */
while (rp != end)
*rp++ = *np++ = ' ';
}
void
cursupdate()
{
LPTR *p;
char c;
int incr, nlines;
int i;
int didincr;
if (bufempty()) { /* special case - file is empty */
*Topchar = *Filemem;
*Curschar = *Filemem;
} else if (LINEOF(Curschar) < LINEOF(Topchar)) {
nlines = cntllines(Curschar, Topchar);
/*
* if the cursor is above the top of the screen, put it at the top of
* the screen..
*/
*Topchar = *Curschar;
Topchar->index = 0;
/*
* ... and, if we weren't very close to begin with, we scroll so that
* the line is close to the middle.
*/
if (nlines > Rows / 3) {
for (i = 0, p = Topchar; i < Rows / 3; i++, *Topchar = *p)
if ((p = prevline(p)) == NULL)
break;
} else
s_ins(0, nlines - 1);
updateNextscreen();
} else if (LINEOF(Curschar) >= LINEOF(Botchar)) {
nlines = cntllines(Botchar, Curschar);
/*
* If the cursor is off the bottom of the screen, put it at the top
* of the screen.. ... and back up
*/
if (nlines > Rows / 3) {
p = Curschar;
for (i = 0; i < (2 * Rows) / 3; i++)
if ((p = prevline(p)) == NULL)
break;
*Topchar = *p;
} else {
scrollup(nlines);
}
updateNextscreen();
}
Cursrow = Curscol = Cursvcol = 0;
for (p = Topchar; p->linep != Curschar->linep; p = nextline(p))
Cursrow += plines(p);
Cline_row = Cursrow;
Cline_size = plines(p);
for (i = 0; i <= Curschar->index; i++) {
c = Curschar->linep->s[i];
/* A tab gets expanded, depending on the current column */
if (c == TAB && !P(P_LS))
incr = P(P_TS) - (Curscol % P(P_TS));
else
incr = chars[c].ch_size;
Curscol += incr;
Cursvcol += incr;
if (Curscol >= Columns) {
Curscol -= Columns;
Cursrow++;
didincr = TRUE;
} else
didincr = FALSE;
}
if (didincr)
Cursrow--;
if (c == TAB && State == NORMAL && !P(P_LS)) {
Curscol--;
Cursvcol--;
} else {
Curscol -= incr;
Cursvcol -= incr;
}
if (Curscol < 0)
Curscol += Columns;
if (set_want_col) {
Curswant = Cursvcol;
set_want_col = FALSE;
}
}
/*
* The rest of the routines in this file perform screen manipulations. The
* given operation is performed physically on the screen. The corresponding
* change is also made to the internal screen image. In this way, the editor
* anticipates the effect of editing changes on the appearance of the screen.
* That way, when we call screenupdate a complete redraw isn't usually
* necessary. Another advantage is that we can keep adding code to anticipate
* screen changes, and in the meantime, everything still works.
*/
/*
* s_ins(row, nlines) - insert 'nlines' lines at 'row'
*/
void
s_ins(row, nlines)
int row;
int nlines;
{
char *s, *d; /* src & dest for block copy */
char *e; /* end point for copy */
int i;
if ((T_IL[0] == NUL) || RedrawingDisabled || nlines <= 0)
return;
/*
* It "looks" better if we do all the inserts at once
*/
outstr(T_SC); /* save position */
if (T_IL_B[0] == NUL) {
for (i = 0; i < nlines; i++) {
windgoto(row, 0);
outstr(T_IL);
}
} else {
windgoto(row, 0);
outstr(T_IL);
if (nlines >= 10)
outchar((char) (nlines / 10 + '0'));
outchar((char) (nlines % 10 + '0'));
outstr(T_IL_B);
}
windgoto(Rows - 1, 0); /* delete any garbage that may have */
outstr(T_EL); /* been shifted to the bottom line */
outstr(T_RC); /* restore the cursor position */
/*
* Now do a block move to update the internal screen image
*/
d = Realscreen + (Columns * (Rows - 1)) - 1;
s = d - (Columns * nlines);
e = Realscreen + (Columns * row);
while (s >= e)
*d-- = *s--;
/*
* Clear the inserted lines
*/
s = Realscreen + (row * Columns);
e = s + (nlines * Columns);
while (s < e)
*s++ = ' ';
}
/*
* s_del(row, nlines) - delete 'nlines' lines at 'row'
*/
void
s_del(row, nlines)
int row;
int nlines;
{
char *s, *d, *e;
int i;
if ((T_DL[0] == NUL) || RedrawingDisabled || nlines <= 0)
return;
outstr(T_SC); /* save position */
windgoto(Rows - 1, 0); /* delete any garbage that */
outstr(T_EL); /* was on the status line */
/* delete the lines */
if (T_DL_B[0] == NUL) {
for (i = 0; i < nlines; i++) {
windgoto(row, 0);
outstr(T_DL); /* delete a line */
}
} else {
windgoto(row, 0);
outstr(T_DL);
if (nlines >= 10)
outchar((char) (nlines / 10 + '0'));
outchar((char) (nlines % 10 + '0'));
outstr(T_DL_B);
}
outstr(T_RC); /* restore position */
/*
* do a block move to update the internal image
*/
d = Realscreen + (row * Columns);
s = d + (nlines * Columns);
e = Realscreen + ((Rows - 1) * Columns);
while (s < e)
*d++ = *s++;
while (d < e) /* clear the lines at the bottom */
*d++ = ' ';
}
SHAR_EOF
cat << \SHAR_EOF > search.c
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!watcgl!grwalter
*/
#include "stevie.h"
#ifdef AMIGA
#include "/regexp/regexp.h"
#else
#include <regexp.h> /* Henry Spencer's regular expression
* routines */
#endif
#ifdef MEGAMAX
overlay "search"
#endif
/*
* This file contains various searching-related routines. These fall into
* three groups: string searches (for /, ?, n, and N), character searches
* within a single line (for f, F, t, T, etc), and "other" kinds of searches
* like the '%' command, and 'word' searches.
*/
/*
* String searches
*
* The actual searches are done using Henry Spencer's regular expression
* library.
*/
#define BEGWORD "([^a-zA-Z0-9_]|^)" /* replaces "\<" in search strings */
#define ENDWORD "([^a-zA-Z0-9_]|$)" /* likewise replaces "\>" */
bool_t begword; /* does the search include a 'begin word'
* match */
/*
* mapstring(s) - map special backslash sequences
*/
static char *
mapstring(s)
char *s;
{
static char ns[MAX_COLUMNS + 1];
char *p;
begword = FALSE;
for (p = ns; *s; s++) {
if (*s != '\\') { /* not an escape */
*p++ = *s;
continue;
}
switch (*++s) {
case '/':
*p++ = '/';
break;
case '<':
strcpy(p, BEGWORD);
p += strlen(BEGWORD);
begword = TRUE;
break;
case '>':
strcpy(p, ENDWORD);
p += strlen(ENDWORD);
break;
default:
*p++ = '\\';
*p++ = *s;
break;
}
}
*p++ = NUL;
return ns;
}
static LPTR *
bcksearch(str)
char *str;
{
static LPTR infile;
LPTR *p;
regexp *prog;
char *s;
int i;
bool_t want_start = (*str == '^'); /* looking for start of line? */
char *match;
/* make sure str isn't empty */
if (str == NULL || *str == NUL)
return NULL;
if ((prog = regcomp(str)) == NULL) {
emsg("Invalid search string");
return NULL;
}
p = Curschar;
dec(p);
if (begword) /* so we don't get stuck on one match */
dec(p);
i = (want_start) ? 0 : p->index;
do {
s = p->linep->s;
if (regexec(prog, s)) { /* match somewhere on line */
if (want_start) { /* could only have been one */
infile.linep = p->linep;
infile.index = (int) (prog->startp[0] - s);
free((char *) prog);
return (&infile);
}
/*
* Now, if there are multiple matches on this line, we have to
* get the last one. Or the last one before the cursor, if we're
* on that line.
*/
match = prog->startp[0];
while (regexec(prog, prog->endp[0])) {
if ((i >= 0) && ((prog->startp[0] - s) > i))
break;
match = prog->startp[0];
}
if ((i >= 0) && ((match - s) > i)) {
i = -1;
continue;
}
infile.linep = p->linep;
infile.index = (int) (match - s);
free((char *) prog);
return (&infile);
}
i = -1;
} while ((p = prevline(p)) != NULL);
/*
* If wrapscan isn't set, bag the search now
*/
if (!P(P_WS)) {
free((char *) prog);
return NULL;
}
/* search backward from the end of the file */
p = prevline(Fileend);
do {
s = p->linep->s;
if (regexec(prog, s)) { /* match somewhere on line */
if (want_start) { /* could only have been one */
infile.linep = p->linep;
infile.index = (int) (prog->startp[0] - s);
free((char *) prog);
return (&infile);
}
/*
* Now, if there are multiple matches on this line, we have to
* get the last one.
*/
match = prog->startp[0];
while (regexec(prog, prog->endp[0]))
match = prog->startp[0];
infile.linep = p->linep;
infile.index = (int) (match - s);
free((char *) prog);
return (&infile);
}
if (p->linep == Curschar->linep)
break;
} while ((p = prevline(p)) != NULL);
free((char *) prog);
return NULL;
}
static LPTR *
fwdsearch(str)
char *str;
{
static LPTR infile;
LPTR *p;
regexp *prog;
bool_t want_start = (*str == '^'); /* looking for start of line? */
char *s;
int i;
if ((prog = regcomp(str)) == NULL) {
emsg("Invalid search string");
return NULL;
}
p = Curschar;
i = Curschar->index + 1;
do {
s = p->linep->s + i;
i = 0;
if (regexec(prog, s)) { /* got a match */
/*
* If we wanted the start of a line and we aren't really there,
* then a match doesn't count.
*/
if (want_start && (s != p->linep->s))
continue;
infile.linep = p->linep;
infile.index = (int) (prog->startp[0] - p->linep->s);
free((char *) prog);
return (&infile);
}
} while ((p = nextline(p)) != NULL);
/*
* If wrapscan isn't set, then don't scan from the beginning of the file.
* Just return failure here.
*/
if (!P(P_WS)) {
free((char *) prog);
return NULL;
}
/* search from the beginning of the file to Curschar */
for (p = Filemem; p != NULL; p = nextline(p)) {
s = p->linep->s;
if (regexec(prog, s)) { /* got a match */
infile.linep = p->linep;
infile.index = (int) (prog->startp[0] - s);
free((char *) prog);
return (&infile);
}
if (p->linep == Curschar->linep)
break;
}
free((char *) prog);
return (NULL);
}
static char *laststr = NULL;
static int lastsdir;
static LPTR *
ssearch(dir, str)
int dir; /* FORWARD or BACKWARD */
char *str;
{
LPTR *pos;
if (dir == BACKWARD)
pos = bcksearch(mapstring(str));
else
pos = fwdsearch(mapstring(str));
/*
* This is kind of a kludge, but its needed to make 'beginning of word'
* searches land on the right place.
*/
if (begword) {
if (pos->index != 0)
pos->index += 1;
}
if (laststr != str) {
if (laststr != NULL)
free(laststr);
laststr = strsave(str);
}
lastsdir = dir;
return pos;
}
void
dosearch(dir, str)
int dir;
char *str;
{
LPTR *p;
if ((p = ssearch(dir, str)) == NULL)
msg("Pattern not found");
else {
LPTR savep;
cursupdate();
/* if we're backing up, we make sure the line we're on */
/* is on the screen. */
setpcmark();
*Curschar = savep = *p;
cursupdate();
}
}
void
searchagain(dir)
int dir;
{
if (laststr == NULL)
beep();
else
dosearch(dir, laststr);
lastsdir = dir;
}
#define OTHERDIR(x) (((x) == FORWARD) ? BACKWARD : FORWARD)
void
repsearch(flag)
bool_t flag;
{
int dir = lastsdir;
if (laststr == NULL)
beep();
else
dosearch(flag ? OTHERDIR(lastsdir) : lastsdir, laststr);
lastsdir = dir;
}
/*
* regerror - called by regexp routines when errors are detected.
*/
void
regerror(s)
char *s;
{
emsg(s);
}
/*
* Character Searches
*/
static char lastc = NUL; /* last character searched for */
static int lastcdir; /* last direction of character search */
static int lastctype; /* last type of search ("find" or "to") */
/*
* searchc(c, dir, type)
*
* Search for character 'c', in direction 'dir'. If type is 0, move to the
* position of the character, otherwise move to just before the char.
*/
bool_t
searchc(c, dir, type)
char c;
int dir;
int type;
{
LPTR save;
save = *Curschar; /* save position in case we fail */
lastc = c;
lastcdir = dir;
lastctype = type;
/*
* On 'to' searches, skip one to start with so we can repeat searches in
* the same direction and have it work right.
*/
if (type)
(dir == FORWARD) ? oneright() : oneleft();
while ((dir == FORWARD) ? oneright() : oneleft()) {
if (gchar(Curschar) == c) {
if (type)
(dir == FORWARD) ? oneleft() : oneright();
return TRUE;
}
}
*Curschar = save;
return FALSE;
}
bool_t
crepsearch(flag)
int flag;
{
int dir = lastcdir;
int rval;
if (lastc == NUL)
return FALSE;
rval = searchc(lastc, flag ? OTHERDIR(lastcdir) : lastcdir, lastctype);
lastcdir = dir; /* restore dir., since it may have changed */
return rval;
}
/*
* "Other" Searches
*/
/*
* showmatch - move the cursor to the matching paren or brace
*/
LPTR *
showmatch()
{
static LPTR pos;
int (*move) (), inc(), dec();
char initc = gchar(Curschar); /* initial char */
char findc; /* terminating char */
char c;
int count = 0;
pos = *Curschar; /* set starting point */
switch (initc) {
case '(':
findc = ')';
move = inc;
break;
case ')':
findc = '(';
move = dec;
break;
case '{':
findc = '}';
move = inc;
break;
case '}':
findc = '{';
move = dec;
break;
case '[':
findc = ']';
move = inc;
break;
case ']':
findc = '[';
move = dec;
break;
default:
return (LPTR *) NULL;
}
while ((*move) (&pos) != -1) { /* until end of file */
c = gchar(&pos);
if (c == initc)
count++;
else if (c == findc) {
if (count == 0)
return &pos;
count--;
}
}
return (LPTR *) NULL; /* never found it */
}
/*
* findfunc(dir) - Find the next function in direction 'dir'
*
* Return TRUE if a function was found.
*/
bool_t
findfunc(dir)
int dir;
{
LPTR *curr;
curr = Curschar;
do {
curr = (dir == FORWARD) ? nextline(curr) : prevline(curr);
if (curr != NULL && curr->linep->s[0] == '{') {
setpcmark();
*Curschar = *curr;
return TRUE;
}
} while (curr != NULL);
return FALSE;
}
/*
* The following routines do the word searches performed by the 'w', 'W',
* 'b', 'B', 'e', and 'E' commands.
*/
/*
* To perform these searches, characters are placed into one of three
* classes, and transitions between classes determine word boundaries.
*
* The classes are:
*
* 0 - white space 1 - letters, digits, and underscore 2 - everything else
*/
static int stype; /* type of the word motion being performed */
#define C0(c) (((c) == ' ') || ((c) == '\t') || ((c) == NUL))
#define C1(c) (isalpha(c) || isdigit(c) || ((c) == '_'))
/*
* cls(c) - returns the class of character 'c'
*
* The 'type' of the current search modifies the classes of characters if a 'W',
* 'B', or 'E' motion is being done. In this case, chars. from class 2 are
* reported as class 1 since only white space boundaries are of interest.
*/
static int
cls(c)
char c;
{
if (C0(c))
return 0;
if (C1(c))
return 1;
/*
* If stype is non-zero, report these as class 1.
*/
return (stype == 0) ? 2 : 1;
}
/*
* fwd_word(pos, type) - move forward one word
*
* Returns the resulting position, or NULL if EOF was reached.
*/
LPTR *
fwd_word(p, type)
LPTR *p;
int type;
{
static LPTR pos;
int sclass = cls(gchar(p)); /* starting class */
pos = *p;
stype = type;
/*
* We always move at least one character.
*/
if (inc(&pos) == -1)
return NULL;
if (sclass != 0) {
while (cls(gchar(&pos)) == sclass) {
if (inc(&pos) == -1)
return NULL;
}
/*
* If we went from 1 -> 2 or 2 -> 1, return here.
*/
if (cls(gchar(&pos)) != 0)
return &pos;
}
/* We're in white space; go to next non-white */
while (cls(gchar(&pos)) == 0) {
/*
* We'll stop if we land on a blank line
*/
if (pos.index == 0 && pos.linep->s[0] == NUL)
break;
if (inc(&pos) == -1)
return NULL;
}
return &pos;
}
/*
* bck_word(pos, type) - move backward one word
*
* Returns the resulting position, or NULL if top-of-file was reached.
*/
LPTR *
bck_word(p, type)
LPTR *p;
int type;
{
static LPTR pos;
int sclass = cls(gchar(p)); /* starting class */
pos = *p;
stype = type;
if (dec(&pos) == -1)
return NULL;
/*
* If we're in the middle of a word, we just have to back up to the start
* of it.
*/
if (cls(gchar(&pos)) == sclass && sclass != 0) {
/*
* Move backward to start of the current word
*/
while (cls(gchar(&pos)) == sclass) {
if (dec(&pos) == -1)
return NULL;
}
inc(&pos); /* overshot - forward one */
return &pos;
}
/*
* We were at the start of a word. Go back to the start of the prior
* word.
*/
while (cls(gchar(&pos)) == 0) { /* skip any white space */
/*
* We'll stop if we land on a blank line
*/
if (pos.index == 0 && pos.linep->s[0] == NUL)
return &pos;
if (dec(&pos) == -1)
return NULL;
}
sclass = cls(gchar(&pos));
/*
* Move backward to start of this word.
*/
while (cls(gchar(&pos)) == sclass) {
if (dec(&pos) == -1)
return NULL;
}
inc(&pos); /* overshot - forward one */
return &pos;
}
/*
* end_word(pos, type) - move to the end of the word
*
* There is an apparent bug in the 'e' motion of the real vi. At least on the
* System V Release 3 version for the 80386. Unlike 'b' and 'w', the 'e'
* motion crosses blank lines. When the real vi crosses a blank line in an
* 'e' motion, the cursor is placed on the FIRST character of the next
* non-blank line. The 'E' command, however, works correctly. Since this
* appears to be a bug, I have not duplicated it here.
*
* Returns the resulting position, or NULL if EOF was reached.
*/
LPTR *
end_word(p, type)
LPTR *p;
int type;
{
static LPTR pos;
int sclass = cls(gchar(p)); /* starting class */
pos = *p;
stype = type;
if (inc(&pos) == -1)
return NULL;
/*
* If we're in the middle of a word, we just have to move to the end of
* it.
*/
if (cls(gchar(&pos)) == sclass && sclass != 0) {
/*
* Move forward to end of the current word
*/
while (cls(gchar(&pos)) == sclass) {
if (inc(&pos) == -1)
return NULL;
}
dec(&pos); /* overshot - forward one */
return &pos;
}
/*
* We were at the end of a word. Go to the end of the next word.
*/
while (cls(gchar(&pos)) == 0) { /* skip any white space */
if (inc(&pos) == -1)
return NULL;
}
sclass = cls(gchar(&pos));
/*
* Move forward to end of this word.
*/
while (cls(gchar(&pos)) == sclass) {
if (inc(&pos) == -1)
return NULL;
}
dec(&pos); /* overshot - forward one */
return &pos;
}
SHAR_EOF
cat << \SHAR_EOF > source.doc
Release Notes for STEVIE - Version 3.10a
Source Notes
Tony Andrews - March 6, 1988
Overview
--------
This file provides a brief description of the source code for
Stevie. The data structures are described later as well. For information
specific to porting the editor, see the file 'porting.doc'. This document
is more relevant to people who want to hack on the editor apart from doing
a simple port.
Most of this document was written some time ago so a lot of the
discussion centers on problems related to the Atari ST environment and
compilers. Most of this can be ignored for other systems.
Things You Need
---------------
Stevie has been compiled with both the Alcyon (4.14A) and the
Megamax C compilers. For the posted binary, Megamax was used because
it's less buggy and provides a reasonable malloc(). Ports to other
compilers should be pretty simple. The current ifdef's for ALCYON and
MEGAMAX should point to the potential trouble areas. (See 'porting.doc'
for more information.)
The search code depends on Henry Spencer's regular expression
code. I used a version I got from the net recently (as part of a 'grep'
posting) and had absolutely no trouble compiling it on the ST. Thanks,
Henry!
The file 'getenv.c' contains a getenv routine that may or may
not be needed with your compiler. My version works with Alcyon and
Megamax, under either the Beckemeyer or Gulam shells.
Lastly, you need a decent malloc. Lots of stuff in stevie is
allocated dynamically. The malloc with Alcyon is problematic because
it allocates from the heap between the end of data and the top of stack.
If you make the stack big enough to edit large files, you wind up
wasting space when working with small files. Mallocs that get their memory
from GEMDOS (in fairly large chunks) are much better.
Data Structures
---------------
A brief discussion of the evolution of the data structures will
do much to clarify the code, and explain some of the strangeness you may
see.
In the original version, the file was maintained in memory as a
simple contiguous buffer. References to positions in the file were simply
character pointers. Due to the obvious performance problems inherent in
this approach, I made the following changes.
The file is now represented by a doubly linked list of 'line'
structures defined as follows:
struct line {
struct line *next; /* next line */
struct line *prev; /* previous line */
char *s; /* text for this line */
int size; /* actual size of space at 's' */
unsigned long num; /* line "number" */
};
The members of the line structure are described more completely here:
prev - pointer to the structure for the prior line, or NULL for the
first line of the file
next - like 'prev' but points to the next line
s - points to the contents of the line (null terminated)
size - contains the size of the chunk of space pointed to by s. This
is used so we know when we can add text to a line without getting
more space. When we DO need more space, we always get a little
extra so we don't make so many calls to malloc.
num - This is a pseudo line number that makes it easy to compare
positions within the file. Otherwise, we'd have to traverse
all the links to tell which line came first.
Since character pointers served to mark file positions in the
original, a similar data object was needed for the new data structures.
This purpose is served by the 'lptr' structure which is defined as:
struct lptr {
struct line *linep; /* line we're referencing */
int index; /* position within that line */
};
The member 'linep' points to the 'line' structure for the line containing
the location of interest. The integer 'index' is the offset into the line
data (member 's') of the character to be referenced.
The following typedef's are more commonly used:
typedef struct line LINE;
typedef struct lptr LPTR;
Many operations that were trivial with character pointers had to be
implemented by functions or macros to manipulate LPTR's. Most of these are in
the files 'ptrfunc.c' and 'macros.h'. There you'll find functions to increment,
decrement, and compare LPTR's.
SHAR_EOF
cat << \SHAR_EOF > stevie.doc
STEVIE - Simply Try this Editor for VI Enthusiasts
Quick Reference Card
by
Tony Andrews And G. R. (Fred) Walter
STEVIE may be freely distributed. The source isn't copyrighted or
restricted in any way. If you pass the program along, please include all
the documentation and, if practical, the source as well.
STEVIE used to stand for 'ST Editor for VI Enthusiasts', however since this
editor is used on more machines than just ST's the acronym was changed.
Starting the Editor
-------------------
The following command line forms are supported:
vi [file ...] Edit the specified file(s)
vi -t tag Start at location of the given tag
vi + file Edit file starting at end
vi +n file Edit file starting a line number 'n'
vi +/pat file Edit file starting at pattern 'pat'
If multiple files are given on the command line (using the first form),
the ":n" command goes to the next file, ":p" goes backward in the list,
and ":rew" can be used to rewind back to the start of the file list.
Set Command Options
-------------------
The ":set" command works as usual to set parameters. Each parameter has
a long and an abbreviated name, either of which may be used. Boolean
parameters are set as in:
set showmatch
or cleared by:
set noshowmatch
Numeric parameters are set as in:
set scroll=5
Several parameters may be set with a single command:
set novb sm report=1
To see the status of all parameters use ":set all". Typing ":set" with
no arguments will show only those parameters that have been changed.
The supported parameters, their names, defaults, and descriptions are
shown below:
Full Name Short Default Description
------------------------------------------------------------------------------
vbell vb vb Use visual bell (novb for audible bell)
showmatch sm nosm Showmatch mode
wrapscan ws ws Wrapscan (searches cross file start/end)
errorbells eb noeb Ring bell when error messages are shown
showmode mo nomo Show on status line when in insert mode
backup bk nobk Leave backup in *.bak on file writes
return cr cr End lines with cr-lf when writing
list list nolist Show tabs and newlines graphically
scroll scroll 12 Number of lines to scroll for ^D and ^U
tabstop ts 8 Number of spaces in a tab
report report 5 Min # of lines to report operations on
lines lines 25 Number of lines on the screen
The EXINIT environment variable can be used to modify the default values
on startup as in:
setenv EXINIT="set sm ts=4"
The 'backup' parameter, if set, causes the editor to retain a backup of any
files that are written. During file writes, a backup is always kept for
safety until the write is completed. At that point, the 'backup' parameter
determines whether the backup file is deleted.
In environments (e.g. OS/2 or TOS) where lines are normally terminated by
CR-LF, the 'return' parameter allows files to be written with only a LF
terminator (if the parameter is cleared).
The 'lines' parameter tells the editor how many lines there are on the screen.
This is useful on systems like the ST where various screen resolutions may be
used. By using the 'lines' parameter, different screen sizes can be easily
handled. On the Amiga system window resizes are atomatically detected and
acted upon. It is suggested that one's window be larger than 2 rows and 5
columns.
File Manipulation Commands
--------------------------
:w write the current file
:wq write and quit
:x write (if necessary) and quit
ZZ same as ":x"
:e file edit the named file
:e! re-edit the current file, discarding any changes
:e # edit the alternate file
:w file write the buffer to the named file
:x,y w file write lines x through y to the named file
:r file read the named file into the buffer
:n edit the next file
:p edit the previous file
:rew rewind the file list
:f show the current file name
:f name change the current file name
:ta tag go to the named tag
^] like ":ta" using the current word as the tag
:help display a command summary
The ":help" command can also be invoke with the <HELP> key on the Atari ST
or the Amiga. This actually displays a pretty complete summary of the real vi
with unsupported features indicated appropriately.
The commands above work pretty much like they do in 'vi'. Most of the
commands support a '!' suffix (if appropriate) to discard any pending
changes.
When writing just part of the buffer, the following address forms are
supported:
addr [+- number]
where 'addr' may be one of the following:
a line number
a mark (as in 'a or 'b)
'.' (the current line)
'$' (the last line)
String Searches
---------------
String searches are supported, as in vi, accepting the usual regular
expression syntax. This was done using Henry Spencer's regular expression
library without modification. Tony Andrews added code outside the library to
support the '\<' and '\>' extensions.
Operators
---------
The vi operators (d, c, y, <, and >) work as true operators.
Tags
----
Tags are implemented.
System-Specific Comments
------------------------
The following sections provide additional relevant information for the
systems to which STEVIE has been ported.
Atari ST
--------
The editor has been tested in all three resolutions, although low and
high res. are less tested than medium. The 50-line high res. mode can
be used by setting the 'lines' parameter to 50. Alternatively, the
environment variable 'LINES' can be set. The editor doesn't actively
set the number of lines on the screen. It just operates using the number
of lines it was told.
The arrow keys, as well as the <INSERT>, <HELP>, and <UNDO> keys are
all mapped appropriately.
UNIX
----
The editor has been ported to UNIX System V release 3. This was done
mainly to get some profiling data so I haven't put much effort into
doing the UNIX version right. It's hard-coded for ansi-style escape
sequences and doesn't use the termcap/terminfo routines at all.
OS/2
----
This port was done because the editor that comes with the OS/2 developer's
kit really sucks. Make sure 'ansi' mode is on (using the 'ansi' command).
The OS/2 ansi driver doesn't support insert/delete line, so the display
updates are a little rough, but the editor is fast enough that it isn't
too bothersome. The arrow keys are NOT mapped, so they don't currently do
anything reasonable.
BSD 4.3
-------
This port was done so it could be worked on in a main-frame enviroment.
Amiga
-----
The arrow keys and the help key are supported, as is window re-sizing.
It is strongly suggested that you not try to type in console commands
(alt-esc in some keymaps, plus the appropriate other keys) since STEVIE
captures all console input. If you do type alt-esc then typing '|' will
return you to STEVIE.
Missing Features
----------------
1. Macros with support for function keys.
2. More "set" options.
3. Auto-indent.
4. Many others...
Known Bugs and Problems
-----------------------
1. The yank buffer uses statically allocated memory, so yanks of more than
5K of text will fail. If a delete spans more than 5K, the program asks
for confirmation before proceeding. That way, if you were moving text,
you don't get screwed by the limited yank buffer. You just have to move
smaller chunks at a time. All the internal buffers (yank, redo, etc.)
need to be reworked to allocate memory dynamically.
2. If you stay in insert mode for a long time (around 5K's worth of
characters, including newlines) the insert buffer can overflow.
When this happens you lose your ability to automatically undo the text just
inserted and the redo/undo/(undo of undo) buffers are reset to the
current position.
3. Several other less bothersome glitches...
Character Function Summary
--------------------------
The following list describes the meaning of each character that's used
by the editor. In some cases characters have meaning in both command and
insert mode; these are all described.
^@ The null character. Not used in any mode. This character may not
be present in the file, as is the case with vi.
^B Backward one screen.
^D Scroll the window down one half screen.
^E Scroll the screen up one line.
^F Forward one screen.
^G Same as ":f" command. Displays file information.
^H (BS) Moves cursor left one space in command mode. In insert mode, erases
the last character typed.
^J Move the cursor down one line.
^L Clear and redraw the screen.
^M (CR) Move to the first non-white character in the next line. In insert
mode, a carriage return opens a new line for input.
^N Move the cursor down a line.
^P Move the cursor up a line.
^U Scroll the window up one half screen.
^V Indicates that the next character is should be treated as entered
and not modified (used to enter control characters, etc.).
^Y Scroll the screen down one line.
^[ Escape cancels a pending command in command mode, and is used to
terminate insert mode.
^] Moves to the tag whose name is given by the word in which the cursor
resides.
^` Same as ":e #" if supported (system-dependent).
SPACE Move the cursor right on column.
$ Move to the end of the current line.
% If the cursor rests on a paren '()', brace '{}', or bracket '[]',
move to the matching one.
' Used to move the cursor to a previously marked position, as in
'a or 'b. The cursor moves to the start of the marked line. The
special mark '' refers to the "previous context".
+ Same as carriage return, in command mode.
, Reverse of the last t, T, f, or F command.
- Move to the first non-white character in the previous line.
. Repeat the last edit command.
/ Start of a forward string search command. String searches may be
optionally terminated with a closing slash. To search for a slash
use '\/' in the search string.
0 Move to the start of the current line. Also used within counts.
1-9 Used to add 'count' prefixes to commands.
: Prefix character for "ex" commands.
; Repeat last t, T, f, or F command.
< The 'left shift' operator.
> The 'right shift' operator.
? Same as '/', but search backward.
A Append at the end of the current line.
B Backward one blank-delimited word.
C Change the rest of the current line.
D Delete the rest of the current line.
E End of the end of a blank-delimited word.
F Find a character backward on the current line.
G Go to the given line number (end of file, by default).
H Move to the first non-white char. on the top screen line.
I Insert before the first non-white char. on the current line.
J Join two lines.
L Move to the first non-white char. on the bottom screen line.
M Move to the first non-white char. on the middle screen line.
N Reverse the last string search.
O Open a new line above the current line, and start inserting.
P Put the yank/delete buffer before the current cursor position.
T Reverse search 'upto' the given character.
W Move forward one blank-delimited word.
X Delete one character before the cursor.
Y Yank the current line. Same as 'yy'.
ZZ Exit from the editor, saving changes if necessary.
[[ Move backward one C function.
]] Move forward one C function.
^ Move to the first non-white on the current line.
` Move to the given mark, as with '. The distinction between the two
commands is important when used with operators. I support the
difference correctly. If you don't know what I'm talking about,
don't worry, it won't matter to you.
~ Switch case of character under cursor.
a Append text after the cursor.
b Back one word.
c The change operator.
d The delete operator.
e Move to the end of a word.
f Find a character on the current line.
h Move left one column.
i Insert text before the cursor.
j Move down one line.
k Move up one line.
l Move right one column.
m Set a mark at the current position (e.g. ma or mb).
n Repeat the last string search.
o Open a new line and start inserting text.
p Put the yank/delete buffer after the cursor.
r Replace a character.
s Replace characters.
t Move forward 'upto' the given character on the current line.
u Undo the last edit.
w Move forward one word.
x Delete the character under the cursor.
y The yank operator.
z Redraw the screen with the current line at the top (zRETURN),
the middle (z.), or the bottom (z-).
| Move to the column given by the preceding count.
SHAR_EOF
cat << \SHAR_EOF > stevie.h
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!watcgl!grwalter
*/
/*
* One (and only 1) of the following defines should be uncommented. Most of
* the code is pretty machine-independent. Machine dependent code goes in a
* file like tos.c or unix.c. The only other place where machine dependent
* code goes is term.h for escape sequences.
*/
#ifndef AMIGA
/* #define ATARI Atari ST */
/* #define UNIX System V */
#define BSD BSD 4.3 */
/* #define OS2 Microsoft OS/2 */
/* #define AMIGA Amiga */
#endif
/*
* If ATARI is defined, one of the following compilers must be selected.
*/
#ifdef ATARI
#define MEGAMAX Megamax Compiler */
/* #define ALCYON Alcyon C compiler */
#endif
/*
* If HELP is defined, the :help command shows a vi command summary.
*/
#define HELP /* enable help command */
#include <stdio.h>
#ifndef ATARI
# ifndef UNIX
# ifndef OS2
# include <stdlib.h>
# endif
# endif
#endif
#include <ctype.h>
#include <string.h>
#include "ascii.h"
#include "keymap.h"
#include "param.h"
#include "term.h"
#include "macros.h"
#ifdef AMIGA
/*
* This won't be needed if you have a version of Lattice 4.01 without broken
* break signal handling.
*/
#include <signal.h>
#endif
extern char *strchr();
#define NORMAL 0
#define CMDLINE 1
#define INSERT 2
#define APPEND 3
#define FORWARD 4
#define BACKWARD 5
/*
* Boolean type definition and constants
*/
typedef int bool_t;
#ifndef TRUE
#define FALSE (0)
#define TRUE (1)
#endif
#define SORTOF (2)
#define YES TRUE
#define NO FALSE
#define MAYBE SORTOF
/*
* Maximum screen dimensions
*/
#define MAX_COLUMNS 140L
/*
* Buffer sizes
*/
#define CMDBUFFSIZE MAX_COLUMNS /* size of the command processing buffer */
#define LSIZE 512 /* max. size of a line in the tags file */
#define IOSIZE (1024+1) /* file i/o and sprintf buffer size */
#define YANKSIZE 5200 /* yank buffer size */
#define INSERT_SIZE 5300 /* insert, redo and undo buffer size must be
* bigger than YANKSIZE */
#define REDO_UNDO_SIZE 5400 /* redo, undo and (undo an undo) buffer size
* must be bigger than INSERT_SIZE */
#define READSIZE 5500 /* read buffer size must be bigger than
* YANKSIZE and REDO_UNDO_SIZE */
/*
* SLOP is the amount of extra space we get for text on a line during editing
* operations that need more space. This keeps us from calling malloc every
* time we get a character during insert mode. No extra space is allocated
* when the file is initially read.
*/
#define SLOP 10
/*
* LINEINC is the gap we leave between the artificial line numbers. This
* helps to avoid renumbering all the lines every time a new line is
* inserted.
*/
#define LINEINC 10
#define CHANGED { Changed = TRUE; }
#define UNCHANGED { Changed = FALSE; }
struct line {
struct line *next; /* next line */
struct line *prev; /* previous line */
char *s; /* text for this line */
int size; /* actual size of space at 's' */
unsigned long num; /* line "number" */
};
#define LINEOF(x) ((x)->linep->num)
struct lptr {
struct line *linep; /* line we're referencing */
int index; /* position within that line */
};
typedef struct line LINE;
typedef struct lptr LPTR;
struct charinfo {
char ch_size;
char *ch_str;
};
extern struct charinfo chars[];
extern int State;
extern int Rows;
extern int Columns;
extern char *Realscreen;
extern char *Nextscreen;
extern char *Filename;
extern LPTR *Filemem;
extern LPTR *Fileend;
extern LPTR *Topchar;
extern LPTR *Botchar;
extern LPTR *Curschar;
extern LPTR *Insstart;
extern int Cursrow, Curscol, Cursvcol, Curswant;
extern bool_t set_want_col;
extern int Prenum;
extern bool_t Changed;
extern bool_t RedrawingDisabled;
extern bool_t MustRedrawLine;
extern bool_t MustRedrawScreen;
extern bool_t UndoInProgress;
extern bool_t Binary;
extern char *IObuff;
extern char *Insbuffptr;
extern char *Insbuff;
extern char *Readbuffptr;
extern char *Readbuff;
extern char *Redobuffptr;
extern char *Redobuff;
extern char *Undobuffptr;
extern char *Undobuff;
extern char *UndoUndobuffptr;
extern char *UndoUndobuff;
extern char *Yankbuffptr;
extern char *Yankbuff;
extern char last_command;
extern char last_command_char;
extern char *malloc(), *strcpy();
/* alloc.c */
char *alloc();
char *strsave();
void screenalloc(), filealloc(), freeall();
LINE *newline();
bool_t canincrease();
/* cmdline.c */
void readcmdline();
void dotag();
void msg(), emsg(), smsg();
void gotocmdline();
void wait_return();
/* dec.c */
int dec();
/* edit.c */
void edit(), insertchar(), getout(), scrollup(), scrolldown(), beginline();
bool_t oneright(), oneleft(), oneup(), onedown();
/* fileio.c */
void filemess(), renum();
bool_t readfile(), writeit();
/* updateNextscreen.c */
void updateNextscreen();
/* help.c */
bool_t help();
/* inc.c */
int inc();
/* linefunc.c */
LPTR *nextline(), *prevline(), *coladvance();
/* main.c */
void stuffReadbuff();
void stuffnumReadbuff();
char vgetc();
char vpeekc();
/* mark.c */
void setpcmark(), clrall(), clrmark();
bool_t setmark();
LPTR *getmark();
/* misccmds.c */
bool_t opencmd();
void fileinfo(), inschar(), insstr(), delline();
bool_t delchar();
int cntllines(), plines();
LPTR *gotoline();
/* updateRealscreen.c */
void updateRealscreen();
/* normal.c */
void normal();
void ResetBuffers();
void AppendToRedobuff();
void AppendNumberToRedobuff();
void AppendToUndobuff();
void AppendNumberToUndobuff();
void AppendPositionToUndobuff();
void AppendToUndoUndobuff();
void AppendNumberToUndoUndobuff();
void AppendPositionToUndoUndobuff();
char *mkstr();
/* param.c */
void doset();
/* screen.c */
void nexttoscreen();
void updateline();
void redrawline();
void screenclear();
void cursupdate();
void s_ins(), s_del();
/* search.c */
void dosearch();
void searchagain();
void repsearch();
bool_t searchc(), crepsearch(), findfunc();
LPTR *showmatch();
LPTR *fwd_word(), *bck_word(), *end_word();
/*
* Machine-dependent routines.
*/
#ifdef AMIGA
# include "amiga.h"
#endif
#ifdef BSD
# include "bsd.h"
#endif
#ifdef UNIX
# include "unix.h"
#endif
#ifdef TOS
# include "tos.h"
#endif
#ifdef OS2
# include "os2.h"
#endif
SHAR_EOF
cat << \SHAR_EOF > term.h
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!watcgl!grwalter
*/
/*
* This file contains the machine dependent escape sequences that the editor
* needs to perform various operations. Some of the sequences here are
* optional. Anything not available should be indicated by a null string. In
* the case of insert/delete line sequences, the editor checks the capability
* and works around the deficiency, if necessary.
*
* Currently, insert/delete line sequences are used for screen scrolling. There
* are lots of terminals that have 'index' and 'reverse index' capabilities,
* but no line insert/delete. For this reason, the editor routines s_ins()
* and s_del() should be modified to use 'index' sequences when the line to
* be inserted or deleted at line zero.
*/
/*
* The macro names here correspond (more or less) to the actual ANSI names
*/
#ifdef ATARI
#define T_EL "\033l" /* erase the entire current line */
#define T_IL "\033L" /* insert one line */
#define T_IL_B ""
#define T_DL "\033M" /* delete one line */
#define T_DL_B ""
#define T_SC "\033j" /* save the cursor position */
#define T_ED "\033E" /* erase display (may optionally home cursor) */
#define T_RC "\033k" /* restore the cursor position */
#define T_CI "\033f" /* invisible cursor (very optional) */
#define T_CV "\033e" /* visible cursor (very optional) */
#define T_TP "" /* plain text */
#define T_TI "" /* inverse-video text */
#endif
#ifdef UNIX
/*
* The UNIX sequences are hard-wired for ansi-like terminals. I should really
* use termcap/terminfo, but the UNIX port was done for profiling, not for
* actual use, so it wasn't worth the effort.
*/
#define T_EL "\033[2K" /* erase the entire current line */
#define T_IL "\033[L" /* insert one line */
#define T_IL_B ""
#define T_DL "\033[M" /* delete one line */
#define T_DL_B ""
#define T_ED "\033[2J" /* erase display (may optionally home cursor) */
#define T_SC "\0337" /* save the cursor position */
#define T_RC "\0338" /* restore the cursor position */
#define T_CI "" /* invisible cursor (very optional) */
#define T_CV "" /* visible cursor (very optional) */
#define T_TP "" /* plain text */
#define T_TI "" /* inverse-video text */
#endif
#ifdef BSD
/* The BSD 4.3 sequences are hard-wired for ansi-like terminals. */
#define T_EL "\033[2K" /* erase the entire current line */
#define T_IL "\033[L" /* insert line */
#define T_IL_B ""
#define T_DL "\033[M" /* delete line */
#define T_DL_B ""
#define T_ED "\033[2J" /* erase display (may optionally home cursor) */
#define T_SC "" /* save the cursor position */
#define T_RC "" /* restore the cursor position */
#define T_CI "" /* invisible cursor (very optional) */
#define T_CV "" /* visible cursor (very optional) */
#define T_TP "" /* plain text */
#define T_TI "" /* inverse-video text */
#endif
#ifdef OS2
/*
* The OS/2 ansi console driver is pretty deficient. No insert or delete line
* sequences. The erase line sequence only erases from the cursor to the end
* of the line. For our purposes that works out okay, since the only time
* T_EL is used is when the cursor is in column 0.
*/
#define T_EL "\033[K" /* erase the entire current line */
#define T_IL "" /* insert one line */
#define T_IL_B ""
#define T_DL "" /* delete one line */
#define T_DL_B ""
#define T_ED "\033[2J" /* erase display (may optionally home cursor) */
#define T_SC "\033[s" /* save the cursor position */
#define T_RC "\033[u" /* restore the cursor position */
#define T_CI "" /* invisible cursor (very optional) */
#define T_CV "" /* visible cursor (very optional) */
#define T_TP "" /* plain text */
#define T_TI "" /* inverse-video text */
#endif
#ifdef AMIGA
/*
* The erase line sequence only erases from the cursor to the end of the
* line. For our purposes that works out okay, since the only time T_EL is
* used is when the cursor is in column 0.
*/
#define T_EL "\033[K" /* erase the entire current line */
#define T_IL "\033[" /* insert line */
#define T_IL_B "L"
#define T_DL "\033[" /* delete line */
#define T_DL_B "M"
#define T_ED "\014" /* erase display (may optionally home cursor) */
#define T_RC "" /* restore the cursor position */
#define T_SC "" /* save the cursor position */
#define T_CI "\033[0 p" /* invisible cursor (very optional) */
#define T_CV "\033[1 p" /* visible cursor (very optional) */
#define T_TP "\033[0m" /* plain text */
#define T_TI "\033[7m" /* inverse-video text */
#endif
SHAR_EOF
cat << \SHAR_EOF > updateNextscreen.c
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!watcgl!grwalter
*/
#include "stevie.h"
/*
* updateNextscreen()
*
* Based on the current value of Topchar, transfer a screenfull of stuff from
* Filemem to Nextscreen, and update Botchar.
*/
void
updateNextscreen()
{
int row, col;
register char *screenp = Nextscreen;
LPTR memp;
LPTR save; /* save pos. in case line won't fit */
register char *endscreen;
char *nextrow;
char extra[16];
int nextra = 0;
char c;
int n;
int done;
int srow; /* starting row of the current line */
MustRedrawLine = FALSE;
MustRedrawScreen = TRUE;
save = memp = *Topchar;
/* The number of rows shown is Rows-1. */
/* The last line is the status/command line. */
endscreen = &screenp[(Rows - 1) * Columns];
srow = done = row = col = 0;
while (screenp < endscreen && !done) {
/* Get the next character to put on the screen. */
/*
* The 'extra' array contains the extra stuff that is inserted to
* represent special characters (tabs, and other non-printable stuff.
* The order in the 'extra' array is reversed.
*/
if (nextra > 0)
c = extra[--nextra];
else {
c = gchar(&memp);
if (inc(&memp) == -1)
done = 1;
/*
* when getting a character from the file, we may have to turn it
* into something else on the way to putting it into
* 'Nextscreen'.
*/
if (c == TAB && !P(P_LS)) {
strcpy(extra, " ");
/* tab amount depends on current column */
nextra = ((P(P_TS) - 1) - col % P(P_TS));
c = ' ';
} else if (c == NUL && P(P_LS)) {
extra[0] = NUL;
nextra = 1;
c = '$';
} else if ((n = chars[c].ch_size) > 1) {
char *p;
nextra = 0;
p = chars[c].ch_str;
/* copy 'ch-str'ing into 'extra' in reverse */
while (n > 1)
extra[nextra++] = p[--n];
c = p[0];
}
}
if (c == NUL) {
srow = ++row;
/*
* Save this position in case the next line won't fit on the
* screen completely.
*/
save = memp;
/* get pointer to start of next row */
nextrow = &Nextscreen[row * Columns];
/* blank out the rest of this row */
while (screenp != nextrow)
*screenp++ = ' ';
col = 0;
continue;
}
if (col >= Columns) {
row++;
col = 0;
}
/* store the character in Nextscreen */
*screenp++ = c;
col++;
}
/*
* If we didn't hit the end of the file, and we didn't finish the last
* line we were working on, then the line didn't fit.
*/
if (!done && c != NUL) {
/*
* Clear the rest of the screen and mark the unused lines.
*/
screenp = &Nextscreen[srow * Columns];
while (screenp < endscreen)
*screenp++ = ' ';
for (; srow < (Rows - 1); srow++)
Nextscreen[srow * Columns] = '@';
*Botchar = save;
return;
}
/* make sure the rest of the screen is blank */
while (screenp < endscreen)
*screenp++ = ' ';
/* put '~'s on rows that aren't part of the file. */
if (col != 0)
row++;
while (row < Rows) {
Nextscreen[row * Columns] = '~';
row++;
}
if (done) /* we hit the end of the file */
*Botchar = *Fileend;
else
*Botchar = memp;
}
SHAR_EOF
cat << \SHAR_EOF > updateRealscreen.c
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!watcgl!grwalter
*/
#include "stevie.h"
/*
* updateRealscreen
*
* Transfer the contents of Nextscreen to the screen, using Realscreen to avoid
* unnecessary output.
*/
void
updateRealscreen()
{
register char *np = Nextscreen;
register char *rp = Realscreen;
register char *endscreen;
int row = 0, col = 0;
int gorow = -1, gocol = -1;
if (RedrawingDisabled)
return;
if (!MustRedrawScreen && !MustRedrawLine)
return;
if (MustRedrawLine) {
msg("STEVIE internal error: updateRealscreen called");
sleep(5);
}
endscreen = &np[(Rows - 1) * Columns];
outstr(T_CI); /* disable cursor */
for (; np < endscreen; np++, rp++) {
/* If desired screen (contents of Nextscreen) does not */
/* match what's really there, put it there. */
if (*np != *rp) {
/* if we are positioned at the right place, */
/* we don't have to use windgoto(). */
if (gocol != col || gorow != row) {
/*
* If we're just off by one, don't send an entire esc. seq.
* (this happens a lot!)
*/
if (gorow == row && gocol + 1 == col) {
outchar(*(np - 1));
gocol++;
} else
windgoto(gorow = row, gocol = col);
}
outchar(*rp = *np);
gocol++;
}
if (++col >= Columns) {
col = 0;
row++;
}
}
outstr(T_CV); /* enable cursor again */
MustRedrawLine = FALSE;
MustRedrawScreen = FALSE;
}
SHAR_EOF
# End of shell archive
exit 0
--
Bob Page, U of Lowell CS Dept. page@swan.ulowell.edu ulowell!page
Have five nice days.